/**
 * JAVACC DEMO 1.0
 * @copy right dwusoft company All rights reserved. 
 * @Package com.apache.bid.service.cacheplugins.helper  
 */
package com.apache.bid.service.cacheplugins.helper;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.commons.httpclient.util.DateUtil;

import com.apache.api.vo.ParamsVo;
import com.apache.bid.common.BidCommonUtil;
import com.apache.bid.common.Constant;
import com.apache.bid.common.cache.BidCacheFactory;
import com.apache.bid.common.cache.BidCacheManager;
import com.apache.bid.common.vo.BidItemCacheVo;
import com.apache.bid.entity.BidApply;
import com.apache.bid.entity.BidItemPrice;
import com.apache.bid.entity.BidSession;
import com.apache.bid.manager.BidItemPriceManager;
import com.apache.cache.util.Validator;
import com.apache.tools.DateUtils;
import com.apache.tools.DateUtils.FmtStr;
import com.apache.tools.StrUtil;

/**
 * description:  降价
 * @author Hou Dayu 创建时间：2016-4-7  
 * 
 */
public class ReductionPriceHelper {

	private static ReductionPriceHelper instance;

	private Map<String, String> params = new HashMap<String, String>();
	private transient static boolean ReductionPriceMark = true;
	private ScheduledExecutorService scheduExec;

	private BidItemPriceManager bidItemPriceManager;

	private ReductionPriceHelper() {
	}

	public static ReductionPriceHelper getInstance() {
		if (null == instance) {
			instance = new ReductionPriceHelper();
			instance.privInit();
		}
		return instance;
	}

	private void exeReduction() {//执行降价
		Runnable myRunnable = new Runnable() {
			public void run() {
				do {
					try {
						if (Validator.isEmpty(params) || params.isEmpty()) {
							Thread.sleep(1000l);
							return;
						}
						for (String key : params.keySet()) {
							String itemId = params.get(key);
							instance.run(itemId);
						}
					} catch (Exception e) {
					}
				} while (true);
			}
		};
		scheduExec.scheduleWithFixedDelay(myRunnable, 35000, 10, TimeUnit.MILLISECONDS);
	}

	public synchronized void setParams(String key, String value) {
		if (!params.containsKey(key))
			params.put(key, value);
		if (ReductionPriceMark) {
			ReductionPriceMark = false;
			instance.exeReduction();
		}
	}

	public synchronized void removeParams(String key) {
		params.remove(key);
	}

	public synchronized String getParams(String key) {
		return params.get(key);
	}

	public void init() {
		instance = this;
		//exeReduction();
		scheduExec = Executors.newScheduledThreadPool(1);
	}

	private void privInit() {
		//exeReduction();
		scheduExec = Executors.newScheduledThreadPool(1);
	}

	private synchronized void run(String itemId) {
		BidCacheManager cache = BidCacheFactory.getInstance().getCacheManager("item");
		BidItemCacheVo itemVo = (BidItemCacheVo) cache.getCacheObjectByKey(cache.item_prefix + itemId);
		String objId = "";
		if (!Constant.SETYPE_HD.equals(itemVo.getSessionType())) {
			objId = itemVo.getSessionId();
		} else {
			objId = itemVo.getItemId();
		}
		Constant.getInstance().setJingjiaMap(objId, objId);
		final String key = Constant.getInstance().getJingjiaMap(objId);
		synchronized (key) {
			try {
				if (Constant.getInstance().getItemConfig("statusStop").equals(itemVo.getItemStatus())) {//已结束
					ReductionPriceHelper.getInstance().removeParams(itemId);
					return;
				}
				if (Constant.getInstance().getItemConfig("statusSuspend").equals(itemVo.getItemStatus())) {//暂停中
					return;
				}
				BidItemPrice price = (BidItemPrice) cache.getCacheCloneByKey(cache.item_price_prefix + itemId);
				long nowTime = BidCommonUtil.getMillTime(DateUtils.Now.fmt_yyyyMMdd_HHmmssSSS(),
						FmtStr.yyyyMMdd_HHmmssSSS.toString());
				long firstBidTime = BidCommonUtil.getMillTime(price.getOpenTime(), "yyyy-MM-dd HH:mm:ss");
				if (nowTime <= firstBidTime) {
					return;
				}
				if ("T".equals(itemVo.getvFlag())) {
					vxingBidMode(cache, itemVo, price, nowTime);
				} else if (Constant.BIDMODE_HELAN.equals(itemVo.getBidMode())) {
					helanBidMode(cache, itemVo, price, nowTime);
				} else {
					ReductionPriceHelper.getInstance().removeParams(itemVo.getItemId());
				}
			} catch (Exception e) {
			}
		}
	}

	/**
	 * description:  荷兰式降价
	 * 1、bidTimes>=itemNum时结束此行务
	 * 2、降到底价后不再降价并结束此任务
	 * 3、当前时间大于等于closeTime进行降价
	 */
	private void helanBidMode(BidCacheManager cache, BidItemCacheVo itemVo, BidItemPrice price, long nowTime) {
		String reductionTime = StrUtil.doNull(price.getReductionCloseTime(), price.getOpenTime());
		String closetTime = BidCommonUtil.getInstance().getMergeTime(reductionTime, itemVo.getLimitTime());
		long colseTime = BidCommonUtil.getMillTime(reductionTime, "yyyy-MM-dd HH:mm:ss");
		if (nowTime < colseTime) {
			return;
		}
		int bidTimes = Integer.parseInt(StrUtil.doNull(price.getBidTimes(), "0"));
		int itemNum = Integer.parseInt(StrUtil.doNull(itemVo.getItemNum(), "1"));
		if (bidTimes >= itemNum) {
			ReductionPriceHelper.getInstance().removeParams(itemVo.getItemId());
			price.setReductionCloseTime(DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
			price.setCloseTime(DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
			cache.updateCacheObject(cache.item_price_prefix + itemVo.getItemId(), price);
			ParamsVo<BidItemPrice> vo = new ParamsVo<BidItemPrice>();
			vo.setObj(price);
			bidItemPriceManager.editInfo(vo);
			return;
		}
		BigDecimal fall_lowerst_price = new BigDecimal(StrUtil.doNull(itemVo.getFallLowerstPrice(), "0"));
		BigDecimal bidValue = new BigDecimal(StrUtil.doNull(price.getFirstValue(), "0"));
		if (bidValue.compareTo(fall_lowerst_price) <= 0) {//如果降到底价则结束
			ReductionPriceHelper.getInstance().removeParams(itemVo.getItemId());
			ReductionPriceHelper.getInstance().removeParams(itemVo.getItemId());
			price.setReductionCloseTime(DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
			price.setCloseTime(DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
			cache.updateCacheObject(cache.item_price_prefix + itemVo.getItemId(), price);
			ParamsVo<BidItemPrice> vo = new ParamsVo<BidItemPrice>();
			vo.setObj(price);
			bidItemPriceManager.editInfo(vo);
			return;
		}
		BigDecimal incrementValue = new BigDecimal(StrUtil.doNull(itemVo.getIncrementValue(), "0"));
		BigDecimal fistValue = bidValue.subtract(incrementValue);
		if ((bidValue.subtract(incrementValue)).compareTo(fall_lowerst_price) < 0) {//如果小于底价则取底价
			fistValue = fall_lowerst_price;
		}
		price.setFirstValue(String.valueOf(fistValue));
		price.setReductionCloseTime(closetTime);
		String closteTime = BidCommonUtil.getInstance().getMergeTime(closetTime, itemVo.getLimitTime());
		price.setCloseTime(closteTime);
		cache.updateCacheObject(cache.item_price_prefix + itemVo.getItemId(), price);
		ParamsVo<BidItemPrice> vo = new ParamsVo<BidItemPrice>();
		vo.setObj(price);
		bidItemPriceManager.editInfo(vo);
	}

	/**
	 * description:  V型降价
	 * 1、大于openTime+fall_limit_time && bidTimes=0
	 * 2、降到底价后不再降价并结束此任务
	 */
	private void vxingBidMode(BidCacheManager cache, BidItemCacheVo itemVo, BidItemPrice price, long nowTime) {
		if (!"T".equals(itemVo.getvFlag())) {
			ReductionPriceHelper.getInstance().removeParams(itemVo.getItemId());
			return;
		}
		String bidTimes = StrUtil.doNull(price.getBidTimes(), "0");
		if (!"0".equals(bidTimes)) {
			ReductionPriceHelper.getInstance().removeParams(itemVo.getItemId());
			return;
		}
		String reductionTime = StrUtil.doNull(price.getReductionCloseTime(), price.getOpenTime());
		String closetTime = BidCommonUtil.getInstance().getMergeTime(reductionTime, itemVo.getFallLimitTime());
		long redTime = BidCommonUtil.getMillTime(closetTime, "yyyy-MM-dd HH:mm:ss");
		if (nowTime < redTime) {
			return;
		}
		BigDecimal fall_lowerst_price = new BigDecimal(StrUtil.doNull(itemVo.getFallLowerstPrice(), "0"));
		BigDecimal bidValue = new BigDecimal(StrUtil.doNull(price.getFirstValue(), "0"));
		if (bidValue.compareTo(fall_lowerst_price) <= 0) {//如果降到底价则结束
			ReductionPriceHelper.getInstance().removeParams(itemVo.getItemId());
			return;
		}
		BigDecimal fall_decrement = new BigDecimal(StrUtil.doNull(itemVo.getFallDecrement(), "0"));
		BigDecimal fistValue = bidValue.subtract(fall_decrement);
		if ((bidValue.subtract(fall_decrement)).compareTo(fall_lowerst_price) < 0) {//如果小于底价则取底价
			fistValue = fall_lowerst_price;
		}
		price.setFirstValue(String.valueOf(fistValue));
		price.setReductionCloseTime(closetTime);
		cache.updateCacheObject(cache.item_price_prefix + itemVo.getItemId(), price);
		ParamsVo<BidItemPrice> vo = new ParamsVo<BidItemPrice>();
		vo.setObj(price);
		bidItemPriceManager.editInfo(vo);
	}

	/**
	 * description: 处理竞买人可以竞买标的数量  
	 */
	public boolean applyBuyItemNum(BidCacheManager cache, BidItemCacheVo item, BidItemPrice price, BidApply apply) {
		boolean mark = true;
		if (Constant.SETYPE_HD.equals(item.getSessionType())) {//如果是活动则不处理
			return mark;
		}
		BidSession session = (BidSession) cache.getCacheObjectByKey(cache.session_prefix + item.getSessionId());
		if (Constant.BAILCTRL_UN.equals(session.getBailCtrl()) || Constant.BAILCTRL_GD.equals(session.getBailCtrl())) {//不交或固定保证金的情况不处理
			return mark;
		}
		BigDecimal fact_bail = new BigDecimal(StrUtil.doNull(apply.getFactBail(), "0"));
		BigDecimal bail_max = new BigDecimal(StrUtil.doNull(session.getBailMax(), "0"));
		if (!"0".equals(StrUtil.doNull(session.getBailMax(), "0"))) {
			if (fact_bail.compareTo(bail_max) >= 0 && new BigDecimal(1).compareTo(bail_max) < 0) {//等于封顶会值时不处理
				return mark;
			}
		}
		if (Constant.BAILCTRL_NUM.equals(session.getBailCtrl())) {//按数量处理标的数量
			String keyPrefix = BidCacheManager.bailCtrlNum_prefix + item.getSessionId() + "_";
			long count = 0;
			if (cache.checkCacheObject(keyPrefix + apply.getUserName())) {
				count = Long.parseLong(String.valueOf(cache.getCacheObjectByKey(keyPrefix + apply.getUserName())));
			} else {
				ParamsVo<BidItemPrice> vo = new ParamsVo<BidItemPrice>();
				BidItemPrice bip = new BidItemPrice();
				bip.setUserName(apply.getUserName());
				vo.setParams("sessionId", item.getSessionId());
				vo.setMethodKey("ByPropertySessionId");
				count = bidItemPriceManager.countInfo(vo);
			}
			long allowBuyNum = Long.parseLong(StrUtil.doNull(apply.getAllowBuyNum(), "1"));
			if (count + 1 > allowBuyNum) {//大于允许购买数量时不处理
				return false;
			}
			cache.createCacheObject(keyPrefix + apply.getUserName(), String.valueOf(count + 1));
			if (cache.checkCacheObject(keyPrefix + price.getUserName())) {
				String numStr = String.valueOf(cache.getCacheObjectByKey(keyPrefix + price.getUserName()));
				if ("0".equals(numStr))
					return mark;
				cache.createCacheObject(keyPrefix + price.getUserName(), String.valueOf(Integer.parseInt(numStr) - 1));
			}
		} else if (Constant.BAILCTRL_BL.equals(session.getBailCtrl())) {//按比例
			try {
				BigDecimal bail_rate = new BigDecimal(session.getBailRate());//小数如：0.1
				String keyPrefix = BidCacheManager.bailCtrlPrice_prefix + item.getSessionId() + "_";
				BigDecimal count = new BigDecimal(0);
				if (cache.checkCacheObject(keyPrefix + apply.getUserName())) {
					count = new BigDecimal(String.valueOf(cache.getCacheObjectByKey(keyPrefix + apply.getUserName())));
				} else {
					ParamsVo<BidItemPrice> vo = new ParamsVo<BidItemPrice>();
					BidItemPrice bip = new BidItemPrice();
					bip.setUserName(apply.getUserName());
					vo.setParams("sessionId", item.getSessionId());
					vo.setMethodKey("ByFirstValueSessionId");
					List list = bidItemPriceManager.getList(vo);
					if (!Validator.isEmpty(list)) {
						count = new BigDecimal(String.valueOf(list.get(0)));
					}
				}
				BigDecimal firstValue = new BigDecimal(price.getFirstValue());
				if (((firstValue.multiply(bail_rate)).add(count)).compareTo(fact_bail) > 0) {//大于保证金不做处理
					return false;
				}
				cache.createCacheObject(keyPrefix + apply.getUserName(),
						String.valueOf((firstValue.multiply(bail_rate)).add(count)));
				if (cache.checkCacheObject(keyPrefix + price.getUserName())) {
					BigDecimal numStr = new BigDecimal(String.valueOf(cache.getCacheObjectByKey(keyPrefix
							+ price.getUserName())));
					if (numStr.compareTo(new BigDecimal(0)) <= 0)
						return mark;
					cache.createCacheObject(keyPrefix + price.getUserName(),
							String.valueOf(numStr.subtract(firstValue.multiply(bail_rate))));
				}
			} catch (Exception e) {
				return false;
			}
		}
		return mark;
	}

	public void setBidItemPriceManager(BidItemPriceManager bidItemPriceManager) {
		this.bidItemPriceManager = bidItemPriceManager;
	}
}
